package main

import (
	"fmt"
	"strconv"
)

const fileFilter = "All File(*);;EXE File(*.exe);;DLL File(*.dll)"

type Root = ImagePE

type ImagePE struct {
	Dos         ImageDos
	NTHeader    ImageNtHeader
	Section     []ImageSectionHeader
	Space       AlignmentSpase
	SectionData []ImageSectionData
	DebugInfo   []byte
}

func (v *ImagePE) Unmarshal(dec *Decoder, info *ValueInfo) {
	dec.SetArg(v)
	dec.Decode(&v.Dos, &ValueInfo{name: "Dos"})
	dec.Decode(&v.NTHeader, &ValueInfo{name: "NTHeader"})
	sectNum := v.NTHeader.FileHeader.NumberOfSections

	v.Section = make([]ImageSectionHeader, sectNum+1)
	dec.Decode(&v.Section, &ValueInfo{name: "Section"})
	dec.Decode(&v.Space, &ValueInfo{name: "Space"})

	v.SectionData = make([]ImageSectionData, sectNum)
	dec.Decode(&v.SectionData, &ValueInfo{name: "SectionData"})
	dec.Decode(&v.DebugInfo, &ValueInfo{name: "DebugInfo"})

	v.unmarshalDataDirectory(dec)
}

func (v *ImagePE) unmarshalDataDirectory(dec *Decoder) {
	dataDir := v.NTHeader.OptionalHeader.DataDirectory[:]
	pos := dec.Pos()
	defer dec.Seek(pos)

	rva := dataDir[0].VirtualAddress
	if rva != 0 {
		var export ImageExportDirectory
		dec.Seek(v.RvaToRawMast(rva) * 8)
		dec.Decode(&export, &ValueInfo{name: "ImageExportDirectory", info: "导出表"})
	}

	rva = dataDir[1].VirtualAddress
	if rva != 0 {
		var in ImageImportDescriptor
		dec.Seek(v.RvaToRawMast(rva) * 8)
		dec.Decode(&in, &ValueInfo{name: "ImageImportDescriptor", info: "导入表"})
	}

	rva = dataDir[2].VirtualAddress
	if rva != 0 {
		var res ImageResourceDirectory
		dec.Seek(v.RvaToRawMast(rva) * 8)
		dec.Decode(&res, &ValueInfo{name: "ImageResourceDirectory", info: "资源表"})
	}

	rva = dataDir[3].VirtualAddress
	if rva != 0 {
		var except ImageRuntimeFunction
		dec.Seek(v.RvaToRawMast(rva) * 8)
		dec.Decode(&except, &ValueInfo{name: "ImageRuntimeFunction", info: "异常处理表"})
	}

	rva = dataDir[4].VirtualAddress
	if rva != 0 {
		var cert WinCertificate
		dec.Seek(int(rva) * 8)
		newDec := dec.SubDecoder(int(dataDir[4].Size))
		newDec.Decode(&cert, &ValueInfo{name: "WinCertificate", info: "数字签名"})
	}

	rva = dataDir[5].VirtualAddress
	if rva != 0 {
		var reloc []ImageBaseRelocation
		dec.Seek(v.RvaToRawMast(rva) * 8)
		newDec := dec.SubDecoder(int(dataDir[5].Size))
		newDec.Decode(&reloc, &ValueInfo{name: "ImageBaseRelocation", info: "重定位表"})
	}

	rva = dataDir[6].VirtualAddress
	if rva != 0 {
		var dbg ImageDebugDirectory
		dec.Seek(v.RvaToRawMast(rva) * 8)
		dec.Decode(&dbg, &ValueInfo{name: "ImageDebugDirectory", info: "调试信息"})
	}

	rva = dataDir[7].VirtualAddress
	if rva != 0 {
		var arch ImageArchitectureHeader
		dec.Seek(v.RvaToRawMast(rva) * 8)
		newDec := dec.SubDecoder(int(dataDir[7].Size))
		newDec.Decode(&arch, &ValueInfo{name: "ImageArchitectureHeader", info: "版权信息"})
	}

	rva = dataDir[8].VirtualAddress
	if rva != 0 {
		var gp []byte
		dec.Seek(v.RvaToRawMast(rva) * 8)
		newDec := dec.SubDecoder(int(dataDir[8].Size))
		newDec.Decode(&gp, &ValueInfo{name: "GlobalPtr", info: "全局指针(GP)"})
	}

	rva = dataDir[9].VirtualAddress
	if rva != 0 {
		var tls ImageTlsDirectory
		dec.Seek(v.RvaToRawMast(rva) * 8)
		dec.Decode(&tls, &ValueInfo{name: "ImageTlsDirectory", info: "线程局部存储(TLS)"})
	}

	rva = dataDir[10].VirtualAddress
	if rva != 0 {
		var cfg ImageLoadConfigDirectory
		dec.Seek(v.RvaToRawMast(rva) * 8)
		dec.Decode(&cfg, &ValueInfo{name: "ImageLoadConfigDirectory", info: "加载配置表"})
	}

	rva = dataDir[11].VirtualAddress
	if rva != 0 {
		var bound ImageBoundImportDirectory
		dec.Seek(v.RvaToRawMast(rva) * 8)
		dec.Decode(&bound, &ValueInfo{name: "ImageBoundImportDirectory", info: "绑定导入表"})
	}

	rva = dataDir[12].VirtualAddress
	if rva != 0 {
		var importAddr []byte
		dec.Seek(v.RvaToRawMast(rva) * 8)
		newDec := dec.SubDecoder(int(dataDir[12].Size))
		newDec.Decode(&importAddr, &ValueInfo{name: "ImportAddress", info: "导入地址表"})
	}

	rva = dataDir[13].VirtualAddress
	if rva != 0 {
		var delay ImgDelayDescr
		dec.Seek(v.RvaToRawMast(rva) * 8)
		dec.Decode(&delay, &ValueInfo{name: "ImgDelayDescr", info: "延迟导入表"})
	}

	rva = dataDir[14].VirtualAddress
	if rva != 0 {
		var com ImageCor20Header
		dec.Seek(v.RvaToRawMast(rva) * 8)
		newDec := dec.SubDecoder(int(dataDir[14].Size))
		newDec.Decode(&com, &ValueInfo{name: "COM", info: ".NET信息"})
	}
}

func (v *ImagePE) unmarshalData(dec *Decoder, data ImageData, name, info string) {
	if data.VirtualAddress == 0 {
		return
	}
	dec.Seek(v.RvaToRawMast(data.VirtualAddress) * 8)
	newDec := dec.SubDecoder(int(data.Size))
	var temp []byte
	newDec.Decode(&temp, &ValueInfo{name: name, info: info})
}

func (v *ImagePE) RawToRva(raw uint32) (uint32, int) {
	for i, sect := range v.Section {
		pos := sect.PointerToRawData
		if pos == raw {
			return sect.VirtualAddress, i
		} else if (pos < raw) && (raw < pos+sect.SizeOfRawData) {
			return raw - pos + sect.VirtualAddress, i
		}
	}
	return 0, -1
}

func (v *ImagePE) RvaToRaw(rva uint32) (uint32, int) {
	for i, sect := range v.Section {
		va := sect.VirtualAddress
		if va == rva {
			return sect.PointerToRawData, i
		} else if (va < rva) && (rva < va+sect.SizeOfRawData) {
			return rva - va + sect.PointerToRawData, i
		}
	}
	return 0, -1
}

func (v *ImagePE) RvaToRawMast(rva uint32) int {
	raw, index := v.RvaToRaw(rva)
	if index < 0 {
		panic(fmt.Sprintf("unknown RVA: 0x%X", rva))
	}
	return int(raw)
}

/****************** DOS头 **********************/

type ImageDosHeader struct {
	E_magic    MagicDos `info:"DOS标识"`
	E_cblp     uint16
	E_cp       uint16
	E_crlc     uint16
	E_cparhdr  uint16
	E_minalloc uint16
	E_maxalloc uint16
	E_ss       uint16
	E_sp       uint16
	E_csum     uint16
	E_ip       uint16
	E_cs       uint16
	E_lfarlc   uint16
	E_ovno     uint16
	E_res      [4]uint16
	E_oemid    uint16
	E_oeminfo  uint16
	E_res2     [10]uint16
	E_lfanew   uint32 `info:"DOS头长度"`
}

type MagicDos string

func (v *MagicDos) Unmarshal(dec *Decoder, info *ValueInfo) {
	*v = MagicDos(dec.ReadBytes(2))
	if *v != "MZ" { // IMAGE_DOS_SIGNATURE
		panic("file isn't PE format")
	}
}

type ImageDos struct {
	ImageDosHeader
	Data []byte
}

func (v *ImageDos) Unmarshal(dec *Decoder, info *ValueInfo) {
	dec.Decode(&v.ImageDosHeader, &ValueInfo{name: "ImageDosHeader"})
	newDec := dec.SubDecoder(int(v.E_lfanew) - 64)
	newDec.Decode(&v.Data, &ValueInfo{name: "Data"})
	dec.Seek(newDec.Pos())
}

/****************** NT头 **********************/

type ImageNtHeader struct {
	Signature      MagicNtSignature `info:"PE签名"`
	FileHeader     ImageFileHeader
	OptionalHeader ImageOptionalHeader
}

func (v *ImageNtHeader) Is64BitFile() bool {
	return v.FileHeader.SizeOfOptionalHeader == 0xF0
}

type MagicNtSignature []byte

func (v MagicNtSignature) String() string {
	return string(v[:2])
}

func (v *MagicNtSignature) Unmarshal(dec *Decoder, info *ValueInfo) {
	*v = dec.ReadBytes(4)
	if string(*v) != "PE\000\000" {
		panic("file isn't NT of PE format")
	}
}

type ImageFileHeader struct {
	Machine              ImageFileMachine   `info:"运行平台"`
	NumberOfSections     uint16             `info:"区块数目"`
	TimeDateStamp        TimeStamp          `info:"文件创建日期和时间"`
	PointerToSymbolTable uint32             `info:"符号表地址"`
	NumberOfSymbols      uint32             `info:"符号表中符号个数"`
	SizeOfOptionalHeader uint16             `info:"可选头大小"`
	Characteristics      ImageFileCharacter `info:"文件属性"`
}

type ImageFileMachine uint16

func (v ImageFileMachine) String() string {
	textMap := map[uint16]string{
		0x0000: "unknown",                       // IMAGE_FILE_MACHINE_UNKNOWN
		0x01d3: "Matsushita_AM33",               // IMAGE_FILE_MACHINE_AM33
		0x8664: "x64",                           // IMAGE_FILE_MACHINE_AMD64
		0x01c0: "ARM",                           // IMAGE_FILE_MACHINE_ARM
		0x01c4: "ARM_NT",                        // IMAGE_FILE_MACHINE_ARMNT
		0xaa64: "ARM64",                         // IMAGE_FILE_MACHINE_ARM64
		0x0ebc: "EFI_byte_code",                 // IMAGE_FILE_MACHINE_EBC
		0x014c: "Intel_386_or_later",            // IMAGE_FILE_MACHINE_I386
		0x0200: "Intel_Itanium",                 // IMAGE_FILE_MACHINE_IA64
		0x6232: "Loong_Arch32",                  // IMAGE_FILE_MACHINE_LOONGARCH32
		0x6264: "Loong_Arch64",                  // IMAGE_FILE_MACHINE_LOONGARCH64
		0x9041: "Mitsubishi_M32R_little_endian", // IMAGE_FILE_MACHINE_M32R
		0x0266: "MIPS16",                        // IMAGE_FILE_MACHINE_MIPS16
		0x0366: "MIPS_with_FPU",                 // IMAGE_FILE_MACHINE_MIPSFPU
		0x0466: "MIPS16_with_FPU",               // IMAGE_FILE_MACHINE_MIPSFPU16
		0x01f0: "Power_PC_little_endian",        // IMAGE_FILE_MACHINE_POWERPC
		0x01f1: "Power_PC_with_floating_point",  // IMAGE_FILE_MACHINE_POWERPCFP
		0x0166: "MIPS_little_endian",            // IMAGE_FILE_MACHINE_R4000
		0x01a2: "Hitachi_SH3",                   // IMAGE_FILE_MACHINE_SH3
		0x01a3: "Hitachi_SH3_DSP",               // IMAGE_FILE_MACHINE_SH3DSP
		0x01a6: "Hitachi_SH4",                   // IMAGE_FILE_MACHINE_SH4
		0x01a8: "Hitachi_SH5",                   // IMAGE_FILE_MACHINE_SH5
		0x01c2: "Thumb",                         // IMAGE_FILE_MACHINE_THUMB
		0x0169: "MIPS_little_endian_WCE_v2",     // IMAGE_FILE_MACHINE_WCEMIPSV2
	}
	if text, ok := textMap[uint16(v)]; ok {
		return text
	}
	return strconv.Itoa(int(v))
}

type ImageFileCharacter uint16

func (v ImageFileCharacter) String() string {
	// "IMAGE_FILE_" + textMap
	textMap := []string{
		0:  "RELOCS_STRIPPED",
		1:  "EXECUTABLE_IMAGE",
		2:  "LINE_NUMS_STRIPPED",
		3:  "LOCAL_SYMS_STRIPPED",
		4:  "AGGRESIVE_WS_TRIM",
		5:  "LARGE_ADDRESS_AWARE",
		7:  "BYTES_REVERSED_LO",
		8:  "32BIT_MACHINE",
		9:  "DEBUG_STRIPPED",
		10: "REMOVABLE_RUN_FROM_SWAP",
		11: "NET_RUN_FROM_SWAP",
		12: "SYSTEM",
		13: "DLL",
		14: "UP_SYSTEM_ONLY",
		15: "BYTES_REVERSED_HI",
	}
	return fieldString(textMap, uint64(v), 16)
}

type ImageOptionalHeader struct {
	Magic                       MagicNtOptional `info:"可选头类型"`
	MajorLinkerVersion          uint8           `info:"链接器主版本号"`
	MinorLinkerVersion          uint8           `info:"链接器次版本号"`
	SizeOfCode                  uint32          `info:"代码段总大小"`
	SizeOfInitializedData       uint32          `info:"已初始化数据表总大小"`
	SizeOfUninitializedData     uint32          `info:"未初始化数据表总大小"`
	AddressOfEntryPoint         uint32          `info:"程序入口地址"`
	BaseOfCode                  uint32          `info:"代码段起始地址"`
	BaseOfData                  DataBase        `info:"数据段起始地址"`
	ImageBase                   PeUint          `info:"内存首选装载地址"`
	SectionAlignment            uint32          `info:"区块内存中对齐值"`
	FileAlignment               uint32          `info:"区块文件中对齐值"`
	MajorOperatingSystemVersion uint16          `info:"最低系统主版本号"`
	MinorOperatingSystemVersion uint16          `info:"最低系统次版本号"`
	MajorImageVersion           uint16          `info:"映象主版本号"`
	MinorImageVersion           uint16          `info:"映象次版本号"`
	MajorSubsystemVersion       uint16          `info:"最低子系统主版本号"`
	MinorSubsystemVersion       uint16          `info:"最低子系统次版本号"`
	Win32VersionValue           uint32
	SizeOfImage                 uint32           `info:"映象大小"`
	SizeOfHeaders               uint32           `info:"文件头大小"`
	CheckSum                    uint32           `info:"校验和"`
	Subsystem                   MagicNtSubsystem `info:"子系统类型"`
	DllCharacteristics          uint16           `info:"DLL属性"`
	SizeOfStackReserve          PeUint           `info:"栈大小"`
	SizeOfStackCommit           PeUint           `info:"实际提交栈大小"`
	SizeOfHeapReserve           PeUint           `info:"堆大小"`
	SizeOfHeapCommit            PeUint           `info:"实际提交堆大小"`
	LoaderFlags                 uint32
	NumberOfRvaAndSizes         uint32
	DataDirectory               ImageDataDirectory `info:"数据目录表"`
}

type DataBase uint32

func (v *DataBase) Unmarshal(dec *Decoder, info *ValueInfo) {
	pe, ok := dec.Arg().(*ImagePE)
	if !ok || pe == nil {
		panic("decode arg not set")
	}
	if !pe.NTHeader.Is64BitFile() {
		var vt uint32
		dec.Decode(&vt, info)
		*v = DataBase(vt)
	}
}

type PeUint uint64

func (v *PeUint) Unmarshal(dec *Decoder, info *ValueInfo) {
	pe, ok := dec.Arg().(*ImagePE)
	if !ok || pe == nil {
		panic("decode arg not set")
	}

	if pe.NTHeader.Is64BitFile() {
		var vt uint64
		dec.Decode(&vt, info)
		*v = PeUint(vt)
	} else {
		var vt uint32
		dec.Decode(&vt, info)
		*v = PeUint(vt)
	}
}

type MagicNtOptional uint16

func (v MagicNtOptional) String() string {
	text := ""
	switch v {
	case 0x10b: // IMAGE_NT_OPTIONAL_HDR32_MAGIC
		text = "NtHeader32"
	case 0x20b: // IMAGE_NT_OPTIONAL_HDR64_MAGIC
		text = "NtHeader64"
	case 0x107: // IMAGE_ROM_OPTIONAL_HDR_MAGIC
		text = "RomHeader"
	default:
		text = strconv.Itoa(int(v))
	}
	return text
}

type MagicNtSubsystem uint16

func (v MagicNtSubsystem) String() string {
	// "IMAGE_SUBSYSTEM_" + textMap
	textMap := []string{
		0:  "UNKNOWN",
		1:  "NATIVE",
		2:  "WINDOWS_GUI",
		3:  "WINDOWS_CUI",
		5:  "OS2_CUI",
		7:  "POSIX_CUI",
		8:  "NATIVE_WINDOWS",
		9:  "WINDOWS_CE_GUI",
		10: "EFI_APPLICATION",
		11: "EFI_BOOT_SERVICE_DRIVER",
		12: "EFI_RUNTIME_DRIVER",
		13: "EFI_ROM",
		14: "IMAGE_SUBSYSTEM_XBOX",
	}
	if int(v) < len(textMap) && len(textMap[v]) > 0 {
		return textMap[v]
	}
	return strconv.Itoa(int(v))
}

type ImageDataDirectory [16]ImageData
type ImageData struct {
	VirtualAddress uint32
	Size           uint32
}

func (v *ImageDataDirectory) Unmarshal(dec *Decoder, info *ValueInfo) {
	infoList := [16]string{"导出表", "导入表", "资源表", "异常处理表",
		"数字签名", "重定位表", "调试信息", "版权信息",
		"全局指针(GP)", "线程局部存储(TLS)", "加载配置表", "绑定导入表",
		"导入地址表", "延迟导入表", ".NET信息", ""}
	for i := 0; i < 16; i++ {
		dec.Decode(&v[i], &ValueInfo{name: strconv.Itoa(i), info: infoList[i]})
	}
}

/****************** 节区表 **********************/

type ImageSectionHeader struct {
	Name                 SectionName      `info:"区块名"`
	VirtualSize          uint32           `info:"区块大小"`
	VirtualAddress       uint32           `info:"内存装载地址"`
	SizeOfRawData        uint32           `info:"文件占用大小"`
	PointerToRawData     uint32           `info:"文件偏移地址"`
	PointerToRelocations uint32           `info:"重定位偏移"`
	PointerToLinenumbers uint32           `info:"行号表偏移"`
	NumberOfRelocations  uint16           `info:"重定位项数"`
	NumberOfLinenumbers  uint16           `info:"行号表数目"`
	Characteristics      SectionCharacter `info:"区块属性"`
}

func (v *ImageSectionHeader) String() string {
	return v.Name.String()
}

type SectionName []byte

func (v *SectionName) Unmarshal(dec *Decoder, info *ValueInfo) {
	*v = dec.ReadBytes(8)
}

func (v SectionName) String() string {
	n := 0
	for n < len(v) && v[n] != 0 {
		n++
	}
	return string(v[:n])
}

type SectionCharacter uint32

func (v SectionCharacter) String() string {
	// "IMAGE_SCN_" + textMap
	textMap := []string{
		0:  "TYPE_DSECT",
		1:  "TYPE_NOLOAD",
		2:  "TYPE_GROUP",
		3:  "TYPE_NO_PAD",
		4:  "TYPE_COPY",
		5:  "CNT_CODE",
		6:  "CNT_INITIALIZED_DATA",
		7:  "CNT_UNINITIALIZED_DATA",
		8:  "LNK_OTHER",
		9:  "LNK_INFO",
		10: "TYPE_OVER",
		11: "LNK_REMOVE",
		12: "LNK_COMDAT",
		15: "MEM_FARDATA",
		17: "MEM_16BIT",
		18: "MEM_LOCKED",
		19: "MEM_PRELOAD",

		20: "ALIGN_1BYTES",
		21: "ALIGN_2BYTES",
		22: "ALIGN_8BYTES",
		23: "ALIGN_128BYTES",

		24: "LNK_NRELOC_OVFL",
		25: "MEM_DISCARDABLE",
		26: "MEM_NOT_CACHED",
		27: "MEM_NOT_PAGED",
		28: "MEM_SHARED",
		29: "MEM_EXECUTE",
		30: "MEM_READ",
		31: "MEM_WRITE",
	}
	return fieldString(textMap, uint64(v), 32)
}

/****************** 节区 **********************/

type ImageSectionData struct {
	Data  []byte
	Space AlignmentSpase
	index int
	name  string
}

func (v *ImageSectionData) Unmarshal(dec *Decoder, info *ValueInfo) {
	pe, ok := dec.Arg().(*ImagePE)
	if !ok || pe == nil {
		panic("decode arg not set")
	}

	off := (dec.Pos() + 7) / 8
	v.index = -1
	for i, sect := range pe.Section {
		if sect.PointerToRawData == uint32(off) {
			v.index = i
			break
		}
	}
	if v.index < 0 {
		panic("unknow section at: " + strconv.Itoa(off))
	}
	length := pe.Section[v.index].SizeOfRawData
	size := pe.Section[v.index].VirtualSize

	if size <= length {
		v.Data = dec.ReadBytes(int(size))
		dec.Decode(&v.Space, &ValueInfo{name: "Space"})
	} else {
		v.Data = dec.ReadBytes(int(length))
	}
	v.name = pe.Section[v.index].Name.String()
}

func (v ImageSectionData) String() string {
	return v.name
}

type AlignmentSpase []byte

func (v *AlignmentSpase) Unmarshal(dec *Decoder, info *ValueInfo) {
	pe, ok := dec.Arg().(*ImagePE)
	if !ok || pe == nil {
		panic("decode arg not set")
	}
	align := pe.NTHeader.OptionalHeader.FileAlignment

	oft := (dec.Pos() + 7) / 8
	spaceLen := ((oft-1)/int(align)+1)*int(align) - oft
	*v = dec.ReadBytes(spaceLen)
}

func (v AlignmentSpase) String() string {
	return ""
}

/****************** 导出表 **********************/

type RvaString string

func NewRvaString(dec *Decoder, info string, rva uint32) RvaString {
	if rva == 0 {
		return ""
	}
	pe, ok := dec.Arg().(*ImagePE)
	if !ok || pe == nil {
		panic("decode arg not set")
	}

	pos := dec.Pos()
	defer dec.Seek(pos)

	str := ""
	dec.Seek(pe.RvaToRawMast(rva) * 8)
	dec.Decode(&str, &ValueInfo{name: "RvaString", info: info})
	return RvaString(str)
}

func (v *RvaString) Unmarshal(dec *Decoder, info *ValueInfo) {
	var rva uint32
	dec.Decode(&rva, info)
	*v = NewRvaString(dec, info.info, rva)
}

type ImageExportDirectory ExportDirectory
type ExportDirectory struct {
	Characteristics       uint32
	TimeDateStamp         TimeStamp `info:"创建时间"`
	MajorVersion          uint16    `info:"主版本号"`
	MinorVersion          uint16    `info:"次版本号"`
	Name                  RvaString `info:"名称"`
	Base                  uint32    `info:"基数"`
	NumberOfFunctions     uint32    `info:"函数个数"`
	NumberOfNames         uint32    `info:"名称个数"`
	AddressOfFunctions    uint32    `info:"函数表地址"`
	AddressOfNames        uint32    `info:"名称表地址"`
	AddressOfNameOrdinals uint32    `info:"输出序号地址"`
}

func (v *ImageExportDirectory) Unmarshal(dec *Decoder, info *ValueInfo) {
	pe, ok := dec.Arg().(*ImagePE)
	if !ok || pe == nil {
		panic("decode arg not set")
	}

	dir := pe.NTHeader.OptionalHeader.DataDirectory[0]
	if dir.VirtualAddress == 0 {
		return
	}
	raw := pe.RvaToRawMast(dir.VirtualAddress)
	if dec.Pos() != raw*8 {
		panic("pos of ImageExportDirectory error")
	}

	dec.Decode((*ExportDirectory)(v), &ValueInfo{name: "ExportDirectory"})

	var funcs []byte
	funcRaw := pe.RvaToRawMast(v.AddressOfFunctions)
	dec.Seek(funcRaw * 8)
	newDec := dec.SubDecoder(4 * int(v.NumberOfFunctions))
	newDec.Decode(&funcs, &ValueInfo{info: "导出函数地址表"})

	names := make([]RvaString, v.NumberOfNames)
	dec.Seek(pe.RvaToRawMast(v.AddressOfNames) * 8)
	dec.Decode(&names, &ValueInfo{info: "导出函数名地址表"})
	ordinals := make([]uint16, v.NumberOfNames)
	dec.Seek(pe.RvaToRawMast(v.AddressOfNameOrdinals) * 8)
	dec.Decode(&ordinals, &ValueInfo{info: "输出序号表"})
	nameMap := make(map[uint16]string)
	for i, s := range names {
		nameMap[ordinals[i]] = string(s)
	}

	dec.Seek(funcRaw * 8)
	for i := uint32(0); i < v.NumberOfFunctions; i++ {
		addr := uint32(0)
		dec.Decode(&addr, &ValueInfo{name: strconv.Itoa(int(v.Base + i)), info: nameMap[uint16(i)]})
	}

	dec.Seek((raw + int(dir.Size)) * 8)
}

/****************** 导入表 **********************/

type ImageImportDescriptor []ImportDescriptor
type ImportDescriptor struct {
	OriginalFirstThunk uint32 `info:"输入名称表(INT)地址"`
	TimeDateStamp      uint32
	ForwarderChain     uint32    `info:"重定向API索引"`
	Name               RvaString `info:"DLL名"`
	FirstThunk         uint32    `info:"输入地址表(IAT)地址"`
}

func (v *ImageImportDescriptor) Unmarshal(dec *Decoder, info *ValueInfo) {
	pe, ok := dec.Arg().(*ImagePE)
	if !ok || pe == nil {
		panic("decode arg not set")
	}

	dir := pe.NTHeader.OptionalHeader.DataDirectory[1]
	if dir.VirtualAddress == 0 {
		return
	}
	raw := pe.RvaToRawMast(dir.VirtualAddress)
	if dec.Pos() != raw*8 {
		panic("pos of ImageImportDescriptor error")
	}

	for i := 0; true; i++ {
		var in ImportDescriptor
		dec.Decode(&in, &ValueInfo{name: strconv.Itoa(i)})
		*v = append(*v, in)
		if in.FirstThunk == 0 {
			break
		}
	}

	thunkSize := 4
	var addr any
	flag := uint64(0x80000000)
	if pe.NTHeader.Is64BitFile() {
		thunkSize = 8
		flag = 0x8000000000000000
		var t uint64
		addr = &t
	} else {
		var t uint32
		addr = &t
	}

	for i, des := range *v {
		if i+1 == len(*v) {
			break
		}
		var original OriginalThunks
		dec.Seek(pe.RvaToRawMast(des.OriginalFirstThunk) * 8)
		dec.Decode(&original, &ValueInfo{name: "OriginalThunks", info: "输入名称表(INT)"})

		var funcs []byte
		funcRaw := pe.RvaToRawMast(des.FirstThunk)
		dec.Seek(funcRaw * 8)
		newDec := dec.SubDecoder(thunkSize * len(original))
		newDec.Decode(&funcs, &ValueInfo{name: "FunctionThunks", info: "输入地址表(IAT)"})

		dec.Seek(funcRaw * 8)
		for _, ori := range original {
			if ori&flag != 0 {
				id := ori & (flag - 1)
				dec.Decode(addr, &ValueInfo{name: strconv.Itoa(int(id)), info: "序号引入函数地址"})
			} else {
				name := NewImportNameThunk(dec, "", uint32(ori)).String()
				dec.Decode(addr, &ValueInfo{name: name, info: "名称引入函数地址"})
			}
		}
	}

	dec.Seek((raw + int(dir.Size)) * 8)
}

type OriginalThunks []uint64

func (v *OriginalThunks) Unmarshal(dec *Decoder, info *ValueInfo) {
	pe, ok := dec.Arg().(*ImagePE)
	if !ok || pe == nil {
		panic("decode arg not set")
	}

	if pe.NTHeader.Is64BitFile() {
		for i := 0; true; i++ {
			var vt uint64
			dec.Decode(&vt, &ValueInfo{name: strconv.Itoa(i)})
			*v = append(*v, vt)
			if vt == 0 {
				break
			}
		}
	} else {
		for i := 0; true; i++ {
			var vt uint32
			dec.Decode(&vt, &ValueInfo{name: strconv.Itoa(i)})
			*v = append(*v, uint64(vt))
			if vt == 0 {
				break
			}
		}
	}

}

type ImportNameThunk struct {
	Hint uint16 `info:"DLL输出表中序号"`
	Name string
}

func NewImportNameThunk(dec *Decoder, info string, rva uint32) *ImportNameThunk {
	var v ImportNameThunk
	if rva == 0 {
		return &v
	}
	pe, ok := dec.Arg().(*ImagePE)
	if !ok || pe == nil {
		panic("decode arg not set")
	}

	pos := dec.Pos()
	defer dec.Seek(pos)

	dec.Seek(pe.RvaToRawMast(rva) * 8)
	dec.Decode(&v, &ValueInfo{name: "ImportNameThunk", info: info})
	return &v
}

func (v ImportNameThunk) String() string {
	return v.Name
}

/****************** 资源表 **********************/

type ImageResourceDirectory ImageResourceDirectoryL1
type ImageResourceDirectoryL1 struct {
	ResourceDirectory
	Entry []ResourceDirectoryEntryL1
}

func (v *ImageResourceDirectory) Unmarshal(dec *Decoder, info *ValueInfo) {
	pe, ok := dec.Arg().(*ImagePE)
	if !ok || pe == nil {
		panic("decode arg not set")
	}

	dir := pe.NTHeader.OptionalHeader.DataDirectory[2]
	if dir.VirtualAddress == 0 {
		return
	}
	raw := pe.RvaToRawMast(dir.VirtualAddress)
	if dec.Pos() != raw*8 {
		panic("pos of ImageResourceDirectory error")
	}

	dec.Decode((*ImageResourceDirectoryL1)(v), &ValueInfo{name: "ResourceDirectory", info: "资源类型表"})

	dec.Seek((raw + int(dir.Size)) * 8)
}

func (v *ImageResourceDirectoryL1) Unmarshal(dec *Decoder, info *ValueInfo) {
	// 第一层：资源类型
	dec.Decode(&v.ResourceDirectory, &ValueInfo{name: "ResourceDirectory"})
	n := v.NumberOfNamedEntries + v.NumberOfIdEntries
	v.Entry = make([]ResourceDirectoryEntryL1, n)
	dec.Decode(&v.Entry, &ValueInfo{name: "Entry"})

	pos := dec.Pos()
	defer dec.Seek(pos)

	for _, e := range v.Entry {
		var l2 ImageResourceDirectoryL2
		e.Offset.seek(dec)
		dec.Decode(&l2, &ValueInfo{name: e.String(), info: "资源ID表"})
	}
}

type ResourceDirectory struct {
	Characteristics      uint32
	TimeDateStamp        uint32
	MajorVersion         uint16
	MinorVersion         uint16
	NumberOfNamedEntries uint16
	NumberOfIdEntries    uint16
}

type ResourceDirectoryEntryL1 struct {
	Name   ResourceName
	Offset ResourceOffset
}

func (v ResourceDirectoryEntryL1) String() string {
	return string(v.Name)
}

func resourceSeek(dec *Decoder, offset uint32) {
	pe, ok := dec.Arg().(*ImagePE)
	if !ok || pe == nil {
		panic("decode arg not set")
	}

	rva := pe.NTHeader.OptionalHeader.DataDirectory[2].VirtualAddress
	if rva == 0 {
		panic("resource not exist")
	}
	raw := pe.RvaToRawMast(rva)
	dec.Seek((raw + int(offset)) * 8)
}

type ResourceName string

func (v *ResourceName) Unmarshal(dec *Decoder, info *ValueInfo) {
	textMap := [24]string{"", "Cursor", "Bitmap", "Icon", "Menu", "Dialog", "String", "FontDir", "Font",
		"Accelerator", "RCDATA", "MessageTable", "GroupCursor", "", "GroupIcon", "", "Version",
		"DlgInclude", "", "PlugPlay", "VXD", "ANICursor", "ANIIcon", "HTML"}

	var id uint32
	dec.Decode(&id, info)

	if id&0x80000000 != 0 {
		pos := dec.Pos()
		defer dec.Seek(pos)

		var str WString
		resourceSeek(dec, id&0x7FFFFFFF)
		dec.Decode(&str, &ValueInfo{name: "WString", info: info.info})
		*v = ResourceName(str)
	} else if int(id) < len(textMap) && len(textMap[id]) > 0 {
		*v = ResourceName(textMap[id])
	} else if id == 0xF1 {
		*v = "Toolbar"
	} else {
		*v = ResourceName(fmt.Sprintf("ID=#%02X", id))
	}
}

type ResourceOffset uint32

func (v ResourceOffset) seek(dec *Decoder) {
	if v&0x80000000 != 0 {
		resourceSeek(dec, uint32(v)&0x7FFFFFFF)
		return
	}
	pe, ok := dec.Arg().(*ImagePE)
	if !ok || pe == nil {
		panic("decode arg not set")
	}
	dec.Seek(pe.RvaToRawMast(uint32(v)) * 8)
}

type ImageResourceDirectoryL2 struct {
	ResourceDirectory
	Entry []ResourceDirectoryEntryL2
}

func (v *ImageResourceDirectoryL2) Unmarshal(dec *Decoder, info *ValueInfo) {
	// 第二层：资源ID
	dec.Decode(&v.ResourceDirectory, &ValueInfo{name: "ResourceDirectory"})
	n := v.NumberOfNamedEntries + v.NumberOfIdEntries
	v.Entry = make([]ResourceDirectoryEntryL2, n)
	dec.Decode(&v.Entry, &ValueInfo{name: "Entry"})

	pos := dec.Pos()
	defer dec.Seek(pos)

	for _, e := range v.Entry {
		var l3 ImageResourceDirectoryL3
		e.Offset.seek(dec)
		dec.Decode(&l3, &ValueInfo{name: info.name + "-" + e.String(), info: "资源代码页"})
	}
}

type ResourceDirectoryEntryL2 struct {
	Id     ResourceId
	Offset ResourceOffset
}

func (v ResourceDirectoryEntryL2) String() string {
	return string(v.Id)
}

type ResourceId string

func (v *ResourceId) Unmarshal(dec *Decoder, info *ValueInfo) {
	var id uint32
	dec.Decode(&id, info)

	if id&0x80000000 != 0 {
		pos := dec.Pos()
		defer dec.Seek(pos)

		var str WString
		resourceSeek(dec, id&0x7FFFFFFF)
		dec.Decode(&str, &ValueInfo{name: "WString", info: info.info})
		*v = ResourceId(str)
	} else {
		*v = ResourceId(strconv.Itoa(int(id & 0xFFFF)))
	}
}

type ImageResourceDirectoryL3 struct {
	ResourceDirectory
	Language uint32
	Offset   uint32
}

func (v *ImageResourceDirectoryL3) Unmarshal(dec *Decoder, info *ValueInfo) {
	// 第三层：资源代码页
	dec.Decode(&v.ResourceDirectory, &ValueInfo{name: "ResourceDirectory"})
	dec.Decode(&v.Language, &ValueInfo{name: "Language"})
	dec.Decode(&v.Offset, &ValueInfo{name: "Offset"})

	pos := dec.Pos()
	defer dec.Seek(pos)

	var data ResourceDataEntry
	resourceSeek(dec, v.Offset)
	dec.Decode(&data, &ValueInfo{name: "ResourceDataEntry", info: info.name})

	var bs []byte
	raw := dec.Arg().(*ImagePE).RvaToRawMast(data.OffsetToData)
	dec.Seek(raw * 8)
	newDec := dec.SubDecoder(int(data.Size))
	newDec.Decode(&bs, &ValueInfo{name: info.name, info: "资源数据"})
}

type ResourceDataEntry struct {
	OffsetToData uint32 `info:"资源地址"`
	Size         uint32 `info:"资源大小"`
	CodePage     uint32 `info:"代码页"`
	Reserved     uint32
}

/****************** 异常处理表 **********************/

type ImageRuntimeFunction []RuntimeFunctionEntry
type RuntimeFunctionEntry struct {
	BeginAddress     uint32 `info:"起始地址"`
	EndAddress       uint32 `info:"结束地址"`
	ExceptionHandler uint32 `info:"异常处理程序地址"`
	HandlerData      uint32 `info:"程序附加数据地址"`
	PrologEndAddress uint32 `info:"prolog结束地址"`
}

func (v *ImageRuntimeFunction) Unmarshal(dec *Decoder, info *ValueInfo) {
	pe, ok := dec.Arg().(*ImagePE)
	if !ok || pe == nil {
		panic("decode arg not set")
	}

	dir := pe.NTHeader.OptionalHeader.DataDirectory[3]
	if dir.VirtualAddress == 0 {
		return
	}
	raw := pe.RvaToRawMast(dir.VirtualAddress)
	if dec.Pos() != raw*8 {
		panic("pos of ImageRuntimeFunction error")
	}

	var tmp []RuntimeFunctionEntry
	newDec := dec.SubDecoder(int(dir.Size))
	newDec.Decode(&tmp, info)
	dec.Seek(newDec.Pos())
	*v = tmp
}

/****************** 数字签名 **********************/

type WinCertificate struct {
	Length          uint32       `info:"证书大小"`
	Revision        CertRevision `info:"修订级别"`
	CertificateType CertType     `info:"证书类型"`
	Certificate     []byte       `info:"证书内容"`
}

type CertRevision [2]byte

func (v CertRevision) String() string {
	return fmt.Sprintf("%d.%d", v[1], v[0])
}

type CertType uint16

func (v CertType) String() string {
	textMap := []string{
		1: "X509",     // WIN_CERT_TYPE_X509
		2: "PKCS7",    // WIN_CERT_TYPE_PKCS_SIGNED_DATA
		3: "Recerved", // WIN_CERT_TYPE_RESERVED_1
		4: "TSStack",  // WIN_CERT_TYPE_TS_STACK_SIGNED
	}
	if int(v) < len(textMap) && len(textMap[v]) > 0 {
		return textMap[v]
	}
	return fmt.Sprintf("0x%04X", v)
}

/****************** 重定位表 **********************/

type ImageBaseRelocation struct {
	VirtualAddress uint32
	SizeOfBlock    uint32
	TypeOffset     []byte // []uint16
}

func (v *ImageBaseRelocation) Unmarshal(dec *Decoder, info *ValueInfo) {
	dec.Decode(&v.VirtualAddress, &ValueInfo{name: "VirtualAddress", info: "重定位块起始地址"})
	dec.Decode(&v.SizeOfBlock, &ValueInfo{name: "SizeOfBlock", info: "重定位块的长度"})

	newDec := dec.SubDecoder(int(v.SizeOfBlock) - 8)
	newDec.Decode(&v.TypeOffset, &ValueInfo{name: "TypeOffset", info: "导出函数地址表"})
	dec.Seek(newDec.Pos())

	spaceLen := ((v.SizeOfBlock-3)/4+1)*4 - v.SizeOfBlock
	if spaceLen != 0 {
		_ = dec.ReadBytes(int(spaceLen))
	}
}

/****************** 调试信息 **********************/

type ImageDebugDirectory struct {
	Characteristics  uint32
	TimeDateStamp    TimeStamp `info:"创建时间"`
	MajorVersion     uint16    `info:"主版本号"`
	MinorVersion     uint16    `info:"次版本号"`
	Type             uint32    `info:"调试类型"`
	SizeOfData       uint32    `info:"调试数据大小"`
	AddressOfRawData uint32    `info:"数据内存地址"`
	PointerToRawData uint32    `info:"数据文件偏移"`
}

/****************** 版权信息 **********************/

type ImageArchitectureHeader struct {
	AmaskValue    uint8  `bit:"1"` //0 -> new instruction depends on mask bit; 1 -> code section depends on mask bit
	Space1        uint8  `bit:"7"` // MBZ
	AmaskShift    uint8  // Amask bit in question for this fixup
	Space2        uint16 // MBZ
	FirstEntryRVA uint32 // RVA into .arch section to array of ARCHITECTURE_ENTRY's
	Unknowns      []byte
}

/****************** 线程局部存储 **********************/

type ImageTlsDirectory struct {
	StartAddressOfRawData PeUint `info:"存储起始地址"`
	EndAddressOfRawData   PeUint `info:"存储结束地址"`
	AddressOfIndex        PeUint `info:"下标地址"`
	AddressOfCallBacks    PeUint `info:"回调函数数组地址"`
	SizeOfZeroFill        uint32 `info:"空白大小"`
	Characteristics       uint32
}

/****************** 加载配置表 **********************/

type ImageLoadConfigDirectory struct {
	Characteristics               uint32
	TimeDateStamp                 TimeStamp
	MajorVersion                  uint16 `info:"主版本号"`
	MinorVersion                  uint16 `info:"次版本号"`
	GlobalFlagsClear              uint32 `info:"启动时清除全局标志"`
	GlobalFlagsSet                uint32 `info:"启动时设置全局标志"`
	CriticalSectionDefaultTimeout uint32 `info:"关键部分默认超时"`
	DeCommitFreeBlockThreshold    uint32 `info:"返回系统前必须释放的内存"`
	DeCommitTotalFreeThreshold    uint32 `info:"总共释放的内存"`
	LockPrefixTable               uint32 `info:"预加锁表"`
	MaximumAllocationSize         uint32 `info:"最大配置大小"`
	VirtualMemoryThreshold        uint32 `info:"最大内存大小"`
	ProcessHeapFlags              uint32 `info:"进程堆栈标志"`
	ProcessAffinityMask           uint32 `info:"进程内部掩码"`
	CSDVersion                    uint16 `info:"CSD版本"`
	Reserved1                     uint16
	EditList                      uint32
	Reserved                      uint32
}

/****************** 绑定导入表 **********************/

type ImageBoundImportDirectory struct {
	TimeDateStamp               TimeStamp
	OffsetModuleName            BoundRvaStr
	NumberOfModuleForwarderRefs uint16
	ModuleForwarderRefs         []ImageBoundForwarderRef
}

func (v *ImageBoundImportDirectory) Unmarshal(dec *Decoder, info *ValueInfo) {
	pe, ok := dec.Arg().(*ImagePE)
	if !ok || pe == nil {
		panic("decode arg not set")
	}

	dir := pe.NTHeader.OptionalHeader.DataDirectory[11]
	if dir.VirtualAddress == 0 {
		return
	}
	raw := pe.RvaToRawMast(dir.VirtualAddress)
	if dec.Pos() != raw*8 {
		panic("pos of ImageBoundImportDirectory error")
	}

	dec.Decode(&v.TimeDateStamp, &ValueInfo{name: "TimeDateStamp"})
	dec.Decode(&v.OffsetModuleName, &ValueInfo{name: "OffsetModuleName"})
	dec.Decode(&v.NumberOfModuleForwarderRefs, &ValueInfo{name: "NumberOfModuleForwarderRefs"})
	if v.NumberOfModuleForwarderRefs == 0 {
		return
	}
	v.ModuleForwarderRefs = make([]ImageBoundForwarderRef, v.NumberOfModuleForwarderRefs)
	dec.Decode(&v.ModuleForwarderRefs, &ValueInfo{name: "ModuleForwarderRefs"})
}

type BoundRvaStr string

func (v *BoundRvaStr) Unmarshal(dec *Decoder, info *ValueInfo) {
	pe, ok := dec.Arg().(*ImagePE)
	if !ok || pe == nil {
		panic("decode arg not set")
	}

	dir := pe.NTHeader.OptionalHeader.DataDirectory[11]
	var va uint16
	dec.Decode(&va, info)
	*v = BoundRvaStr(NewRvaString(dec, info.info, dir.VirtualAddress+uint32(va)))
}

type ImageBoundForwarderRef struct {
	TimeDateStamp    TimeStamp
	OffsetModuleName BoundRvaStr
	Reserved         uint16
}

func (v ImageBoundForwarderRef) String() string {
	return string(v.OffsetModuleName)
}

/****************** 延迟导入表 **********************/

type ImgDelayDescr struct {
	Attrs     uint32 `info:"属性"`
	DLLName   uint32 `info:"DLL名字地址"`
	Hmod      uint32 `info:"DLL句柄地址"`
	IAT       uint32 `info:"IAT表地址"`
	INT       uint32 `info:"INT表地址"`
	BoundIAT  uint32 `info:"绑定导入表地址"`
	UnloadIAT uint32 `info:"原始IAT的可选拷贝地址"`
	TimeStamp uint32
}

/****************** .NET信息 **********************/

type ImageCor20Header struct {
	// Header versioning
	Cb                  uint32
	MajorRuntimeVersion uint16
	MinorRuntimeVersion uint16
	// Symbol table and startup information
	MetaData        ImageData
	Flags           uint32
	EntryPointToken uint32
	// Binding information
	Resources           ImageData
	StrongNameSignature ImageData
	// Regular fixup and binding information
	CodeManagerTable        ImageData
	VTableFixups            ImageData
	ExportAddressTableJumps ImageData
	// Precompiled image info (internal use only - set to zero)
	ManagedNativeHeader ImageData
	Unknowns            []byte
}
